﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.ComponentModel;
using LibrarySync2.Business.FileSystem;
using LibrarySync2.Common.Event;
using LibrarySync2.Common.Extensions;
using LibrarySync2.Common.Xml;
using LibrarySync2.Business.FileSystem.Update;

namespace LibrarySync2.Business.Worker
{
    public class LibraryComparer
    {
        private DirectoryInfo _localLibraryRootDirectory;
        private FileInfo _tradingPartnerLibraryFile;
        private FileInfo _tradingPartnerBlacklistFile;
        private bool _includeParentDirectoryStructures;

        private BackgroundWorker _analysisWorker;

        public bool Running { get; private set; }

        public FileSystemUpdate ComparisonResults { get; private set; }

        public event EventHandler<ComparisonEventArgs> ComparisonEvent;

        public LibraryComparer(DirectoryInfo localLibraryRootDirectory, FileInfo tradingPartnerLibraryFile, FileInfo tradingPartnerBlacklistFile, bool includeParentDirectoryStructures)
        {
            if (localLibraryRootDirectory == null)
                throw new ArgumentNullException("localLibraryRootDirectory");
            if (tradingPartnerLibraryFile == null)
                throw new ArgumentNullException("tradingPartnerLibraryFile");

            if (!localLibraryRootDirectory.Exists)
                throw new ArgumentException(string.Format(
                    "Local library root directory does not exist: '{0}'", localLibraryRootDirectory.FullName));
            if (!tradingPartnerLibraryFile.Exists)
                throw new ArgumentException(string.Format(
                    "Trading partner library file does not exist: '{0}'", tradingPartnerLibraryFile.FullName));
            if (tradingPartnerBlacklistFile != null && !tradingPartnerBlacklistFile.Exists)
                throw new ArgumentException(string.Format(
                    "Trading partner blacklist file does not exist: '{0}'", tradingPartnerBlacklistFile.FullName));

            _localLibraryRootDirectory = localLibraryRootDirectory;
            _tradingPartnerLibraryFile = tradingPartnerLibraryFile;
            _tradingPartnerBlacklistFile = tradingPartnerBlacklistFile;

            _includeParentDirectoryStructures = includeParentDirectoryStructures;

            _analysisWorker = new BackgroundWorker();
            _analysisWorker.DoWork += new DoWorkEventHandler(_analysisWorker_DoWork);
            _analysisWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(_analysisWorker_RunWorkerCompleted);
        }

        public void Start()
        {
            _analysisWorker.RunWorkerAsync();
        }

        void _analysisWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            Running = true;

            ComparisonEvent.Raise(this, new ComparisonEventArgs("Analyzing local library..."));

            var localLibrary = new Library(_localLibraryRootDirectory);

            var partnerLibrary = _tradingPartnerLibraryFile.LoadSerializedContent<Library>();
            var partnerBlacklist = _tradingPartnerBlacklistFile == null ?
                new Blacklist() :
                _tradingPartnerBlacklistFile.LoadSerializedContent<Blacklist>();

            ComparisonEvent.Raise(this, new ComparisonEventArgs("Identifying library differences..."));

            ComparisonResults = localLibrary.FindDifferences(partnerLibrary, partnerBlacklist, _includeParentDirectoryStructures);
        }

        void _analysisWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            ComparisonEvent.Raise(this, new ComparisonEventArgs("Analysis complete.", ComparisonResults));

            Running = false;
        }
    }
}
